package edu.zjut.hjg.saas.common.support.spring;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.MethodParameter;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;

import edu.zjut.hjg.saas.common.annotation.CookieSessionIn;
import edu.zjut.hjg.saas.common.annotation.CookieSessionOut;
import edu.zjut.hjg.saas.common.util.CookieSessionUtil;

/**
 * 带CookieSession注解的参数处理
 * 
 * @author hjg
 */
public class CookieSessionArgumentResolver implements WebArgumentResolver, ModelAndViewResolver {

    private CookieSessionUtil cookieSessionUtil;

    public void setCookieSessionUtil(CookieSessionUtil cookieSessionUtil) {
        this.cookieSessionUtil = cookieSessionUtil;
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest)
            throws Exception {
        CookieSessionIn in = methodParameter.getMethodAnnotation(CookieSessionIn.class);
        if (in == null || !isRightParam(in, methodParameter)) {
            // 没有CookieSessionIn注解，或者不是该参数
            return WebArgumentResolver.UNRESOLVED;
        }
        // 被标注为CookieSessionIn的参数
        // 先从请求属性中取，如果不存在则从cookie中取，以免多次解析cookie
        String name = in.value();
        Object sessionObject = webRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
        if (sessionObject == null) {
            Class<?> type = methodParameter.getParameterType();
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            sessionObject = cookieSessionUtil.getObjectFromCookieSession(name, type, request);
            if (sessionObject != null) {
                webRequest.setAttribute(name, sessionObject, RequestAttributes.SCOPE_REQUEST);
            }
        }
        return sessionObject;
    }

    @Override
    @SuppressWarnings("unchecked")
    public ModelAndView resolveModelAndView(Method handlerMethod, Class handlerType,
                                            Object returnValue, ExtendedModelMap implicitModel,
                                            NativeWebRequest webRequest) {
        if (handlerMethod.isAnnotationPresent(CookieSessionOut.class)) {
            CookieSessionOut annotation = handlerMethod.getAnnotation(CookieSessionOut.class);
            String name = annotation.value();
            // 这里删除掉，否则会和request属性中内容同名导致异常
            Object object = implicitModel.remove(name);
            // 写cookie，如果object为null，则会删除cookie
            saveOrClearSession(name, object, webRequest);
        }
        return ModelAndViewResolver.UNRESOLVED;
    }

    private void saveOrClearSession(String name, Object object, NativeWebRequest webRequest) {
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        if (object == null) {
            //删除request属性
            webRequest.removeAttribute(name, RequestAttributes.SCOPE_REQUEST);
            cookieSessionUtil.expireCookieSession(name, response);
        } else {
            // 放入request属性中，覆盖原来的值
            webRequest.setAttribute(name, object, RequestAttributes.SCOPE_REQUEST);
            cookieSessionUtil.saveObjectToCookieSession(name, object, response);
        }
    }

    private boolean isRightParam(CookieSessionIn in, MethodParameter methodParameter) {
        String paramName = "".equals(in.param()) ? in.value() : in.param();
        return paramName.equals(methodParameter.getParameterName());
    }
}
